package ch03
{
	import ch03.com.friendsofed.isometric.DrawnIsoBox;
	import ch03.com.friendsofed.isometric.DrawnIsoTile;
	import ch03.com.friendsofed.isometric.IsoUtils;
	import ch03.com.friendsofed.isometric.Point3D;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.MouseEvent;
	import flash.geom.Point;

	/**
	 * 层深测试
	 *
	 * 排序的策略是将所有IsoObject 放入一个数组内，然 后根据对象的depth来排序这个数组，
	   再根据这个数组来安排显示列表内对象的顺序。每次有对象加入时都要重新排序该数组。
	 */
	[SWF(backgroundColor=0xffffff)]
	public class DepthTest extends Sprite
	{
		private var world:Sprite;
		private var objectList:Array;

		public function DepthTest()
		{
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;

			world = new Sprite();
			world.x = stage.stageWidth / 2;
			world.y = 100;
			addChild(world);

			objectList = [];

			/**
			 * 之前的例子中，层深排序表现的还不错，只是偶尔会出现 tile 盖在 box 上面。这是因为
			   当 box 放在 tile 上时，它们的 x,y,z 实际上是一样的，所以计算出来的 depth 也是一样的。在
			   排序的时候，碰到两个一样大小的数字，就无法判断到底谁先谁后了。这个问题有两种处理
			   方式：一种是让 tile 稍微低一点或者让 box 稍微高一点
			   不用太多，足够区别 depth 即可。
			   比如用下面一行代码创建tile：
			   tile.position = new Point3D(i*20, 0.1, j*20);
			   每个tile 比box 都低0.1，即可区别depth，又看不出有什么异样。
			   另一种相对复杂但更具效率的方法，是使用两个 sprite，一个放 tile，一个放 box。事实
			   上，对 400 个纹丝不动的 tile 是没必要一直排序的，它们始终铺在 box 的下方。所以只要把
			   它们放在位于下方的sprite 中，然后只需对含有box 的sprite 进行排序即可。
			 */
			for (var i:int = 0; i < 20; i++)
			{
				for (var j:int = 0; j < 20; j++)
				{
					var tile:DrawnIsoTile = new DrawnIsoTile(20, 0xcccccc);
					tile.position = new Point3D(i * 20, 0.1, j * 20);
					world.addChild(tile);
					objectList.push(tile);
				}
			}
			sortList();
			world.addEventListener(MouseEvent.CLICK, onWorldClick);
		}

		private function onWorldClick(event:MouseEvent):void
		{
			var box:DrawnIsoBox = new DrawnIsoBox(20, Math.random() * 0xffffff, 20);
			var pos:Point3D = IsoUtils.screenToIso(new Point(world.mouseX, world.mouseY));
			pos.x = Math.round(pos.x / 20) * 20;
			pos.y = Math.round(pos.y / 20) * 20;
			pos.z = Math.round(pos.z / 20) * 20;
			box.position = pos;
			world.addChild(box);
			objectList.push(box);
			sortList();
		}

		private function sortList():void
		{
			objectList.sortOn("depth", Array.NUMERIC);
			for each (var dis:DisplayObject in objectList)
			{
				world.addChild(dis);
			}
		}
	}
}